package role

import (
	"context"
	"gf-admin-api-template/internal/dao"
	"gf-admin-api-template/internal/model"
	"gf-admin-api-template/internal/model/do"
	"gf-admin-api-template/internal/model/entity"
	"gf-admin-api-template/internal/service"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
)

type sRole struct{}

func New() *sRole {
	return &sRole{}
}
func init() {
	service.RegisterRole(New())
}

func (r *sRole) List(ctx context.Context, input model.RoleGetListInput) (total int, res []*model.RoleInfo, err error) {
	m := dao.AdminRole.Ctx(ctx).OmitEmpty().
		Where(do.AdminRole{
			Name: input.Name,
			Slug: input.Slug,
		})
	total, err = m.Count()
	if err != nil {
		return
	}
	if total > 0 {
		err = m.Page(input.Page, input.PageSize).
			OrderDesc(dao.AdminRole.Columns().Id).
			Scan(&res)
		if err != nil {
			return
		}
		var roleTemp = make(map[uint]*model.RoleInfo)
		var roleIds []uint
		for _, role := range res {
			roleTemp[role.Id] = role
			roleIds = append(roleIds, role.Id)
		}
		var roleRelMenuList []*entity.AdminRoleRelMenu
		err = dao.AdminRoleRelMenu.Ctx(ctx).WhereIn(dao.AdminRoleRelMenu.Columns().RoleId, roleIds).Scan(&roleRelMenuList)
		if err != nil {
			return
		}
		var menuIds []uint
		for _, relMenu := range roleRelMenuList {
			menuIds = append(menuIds, relMenu.MenuId)
		}
		var menuList []*model.MenuSimpleTreeItem
		menuList, err = service.Menu().GetSimpleListById(ctx, menuIds)
		if err != nil {
			return
		}
		var menuTemp = make(map[uint]*model.MenuSimpleTreeItem)
		for _, menu := range menuList {
			menuTemp[menu.Id] = menu
		}
		for _, roleRelMenu := range roleRelMenuList {
			if menu, ok := menuTemp[roleRelMenu.MenuId]; ok {
				if role, ok1 := roleTemp[roleRelMenu.RoleId]; ok1 {
					role.Menus = append(role.Menus, menu)
				}
			}
		}
	}
	return
}

func (r *sRole) Create(ctx context.Context, in model.RoleCreateInput, menus []uint) error {
	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		id, err := dao.AdminRole.Ctx(ctx).Data(do.AdminRole{
			Name: in.Name,
			Slug: in.Slug,
		}).InsertAndGetId()
		if err != nil {
			return err
		}
		var relIn []*model.RoleRelMenuInput
		for _, menu := range menus {
			da := model.RoleRelMenuInput{
				RoleId: uint(id),
				MenuId: menu,
			}
			relIn = append(relIn, &da)
		}
		_, err = dao.AdminRoleRelMenu.Ctx(ctx).Data(relIn).Insert()
		return err
	})
}

func (r *sRole) Update(ctx context.Context, id uint, in model.RoleCreateInput, menus []uint) error {
	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err := dao.AdminRole.Ctx(ctx).Data(in).Where(dao.AdminRole.Columns().Id, id).Update()
		if err != nil {
			return err
		}
		_, err = dao.AdminRoleRelMenu.Ctx(ctx).Where(dao.AdminRoleRelMenu.Columns().RoleId, id).Delete()
		if err != nil {
			return err
		}
		var relIn []*model.RoleRelMenuInput
		for _, menu := range menus {
			da := model.RoleRelMenuInput{
				RoleId: id,
				MenuId: menu,
			}
			relIn = append(relIn, &da)
		}
		_, err = dao.AdminRoleRelMenu.Ctx(ctx).Data(relIn).Insert()
		return err
	})
}

func (r *sRole) Delete(ctx context.Context, id uint) error {
	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err := dao.AdminRole.Ctx(ctx).Where(dao.AdminRole.Columns().Id, id).Delete()
		if err != nil {
			return err
		}
		_, err = dao.AdminRoleRelMenu.Ctx(ctx).Where(dao.AdminRoleRelMenu.Columns().RoleId, id).Delete()
		return err
	})
}

func (r *sRole) GetListById(ctx context.Context, ids []uint) (res []*entity.AdminRole, err error) {
	err = dao.AdminRole.Ctx(ctx).WhereIn(dao.AdminRole.Columns().Id, ids).Scan(&res)
	return
}

func (r *sRole) GetListByUserId(ctx context.Context, ids []uint) (res []*entity.AdminRole, err error) {
	var relRoleList []*entity.AdminUserRelRole
	err = dao.AdminUserRelRole.Ctx(ctx).WhereIn(dao.AdminUserRelRole.Columns().UserId, ids).Scan(&relRoleList)
	if err != nil {
		return
	}
	var roleIds []uint
	for _, relRole := range relRoleList {
		roleIds = append(roleIds, relRole.RoleId)
	}
	err = dao.AdminRole.Ctx(ctx).WhereIn(dao.AdminRole.Columns().Id, roleIds).Scan(&res)
	return
}
